package org.zjframework.traceframe.common.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.type.Type;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.zjframework.traceframe.common.dao.ICommonDao;
import org.zjframework.traceframe.common.dao.jdbc.JdbcDao;
import org.zjframework.traceframe.common.dao.util.MyBeanUtils;
import org.zjframework.traceframe.common.dao.util.oConvertUtils;
import org.zjframework.traceframe.common.exception.BusinessException;



/**
 *
 * 类描述： DAO层泛型基类
 *
 * @author: 刘倩
 * @date： 日期：2013-10-12 时间：下午14:20:45
 * @param <T>
 * @param <PK>
 * @version 1.0
 */
@SuppressWarnings({ "hiding", "unused" })
@Component("commonDao")
public  class CommonDaoImpl<T, PK extends Serializable> implements ICommonDao{
	/**
	 * 初始化Log4j的一个实例
	 */
	private static final Logger logger = Logger.getLogger(CommonDaoImpl.class);

	/**
	 * 注入一个sessionFactory属性
	 * **/
	@Autowired
	@Qualifier("sessionFactory")
	private SessionFactory sessionFactory;

	public Session getSession() {
		// 事务必须是开启的(Required)，否则获取不到
		return sessionFactory.getCurrentSession();
	}

	/**
	 * 获得该类的属性和类型
	 *
	 * @param entityName
	 *            注解的实体类
	 */
	@SuppressWarnings({ "unused", "rawtypes" })
	public List<String> getProperty(Class entityName) {
		ClassMetadata cm = sessionFactory.getClassMetadata(entityName);
		String[] str = cm.getPropertyNames(); // 获得该类所有的属性名称
        List<String> fieldList = new ArrayList<String>();
		for (int i = 0; i < str.length; i++) {
			String property = str[i];
			String type = cm.getPropertyType(property).getName(); // 获得该名称的类型
			System.out.println(property + "---&gt;" + type);
            fieldList.add(property);
		}
        return fieldList;
	}

	/**
	 * 获取所有数据表
	 * @return
	 */
	public Integer getAllDbTableSize() {
		SessionFactory factory = getSession().getSessionFactory();
		Map<String, ClassMetadata> metaMap = factory.getAllClassMetadata();
		return metaMap.size();
	}

	/**
	 * 根据实体名字获取唯一记录
	 *
	 * @param propertyName
	 * @param value
	 * @return
	 */

	@SuppressWarnings("unchecked")
	public <T> T findUniqueByProperty(Class<T> entityClass, String propertyName, Object value) {
		Assert.hasText(propertyName);
		return (T) createCriteria(entityClass, Restrictions.eq(propertyName, value)).uniqueResult();
	}

	/**
	 * 按属性查找对象列表.
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findByProperty(Class<T> entityClass, String propertyName, Object value) {
		Assert.hasText(propertyName);
		return (List<T>) createCriteria(entityClass, Restrictions.eq(propertyName, value)).list();
	}

	/**
	 * 根据传入的实体持久化对象
	 */
	public <T> void save(T entity) {
		try {
			getSession().save(entity);
			getSession().flush();
			if (logger.isDebugEnabled()) {
				logger.debug("保存实体成功," + entity.getClass().getName());
			}
		} catch (RuntimeException e) {
			logger.error("保存实体异常", e);
			throw e;
		}

	}

	/**
	 * 批量保存数据
	 * @param <T>
	 * @param entitys 要持久化的临时实体对象集合
	 */
	public <T> void batchSave(List<T> entitys) {
		for (int i=0; i<entitys.size();i++) {
			getSession().save(entitys.get(i));
			if (i % 20 == 0) {
				//20个对象后才清理缓存，写入数据库
				getSession().flush();
				getSession().clear();
			}

		}
	}
	/**
	 * 根据传入的实体添加或更新对象
	 *
	 * @param <T>
	 *
	 * @param entity
	 */

	public <T> void saveOrUpdate(T entity) {
		try {
			getSession().saveOrUpdate(entity);
			getSession().flush();
			if (logger.isDebugEnabled()) {
				logger.debug("添加或更新成功," + entity.getClass().getName());
			}
		} catch (RuntimeException e) {
			logger.error("添加或更新异常", e);
			throw e;
		}
	}

	/**
	 * 根据传入的实体删除对象
	 */
	public <T> void delete(T entity) {
		try {
			getSession().delete(entity);
			getSession().flush();
			if (logger.isDebugEnabled()) {
				logger.debug("删除成功," + entity.getClass().getName());
			}
		} catch (RuntimeException e) {
			logger.error("删除异常", e);
			throw e;
		}
	}

	/**
	 * 根据主键删除指定的实体
	 *
	 * @param <T>
	 * @param pojo
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public <T> void deleteEntityById(Class entityName, Serializable id) {
		delete(get(entityName, id));
		getSession().flush();
	}

	/**
	 * 删除全部的实体
	 *
	 * @param <T>
	 *
	 * @param entitys
	 */
	public <T> void deleteAllEntitie(Collection<T> entitys) {
		for (Object entity : entitys) {
			getSession().delete(entity);
			getSession().flush();
		}
	}

	/**
	 * 根据Id获取对象。
	 */
	@SuppressWarnings("unchecked")
	public <T> T get(Class<T> entityClass, final Serializable id) {

		return (T) getSession().get(entityClass, id);

	}

	/**
	 * 根据主键获取实体并加锁。
	 *
	 * @param <T>
	 * @param entityName
	 * @param id
	 * @param lock
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public <T> T getEntity(Class entityName, Serializable id) {

		T t = (T) getSession().get(entityName, id);
		if (t != null) {
			getSession().flush();
		}
		return t;
	}

	/**
	 * 更新指定的实体
	 *
	 * @param <T>
	 * @param pojo
	 */
	public <T> void updateEntitie(T pojo) {
		getSession().update(pojo);
		getSession().flush();
	}

	/**
	 * 更新指定的实体
	 *
	 * @param <T>
	 * @param pojo
	 */
	public <T> void updateEntitie(String className, Object id) {
		getSession().update(className, id);
		getSession().flush();
	}

	/**
	 * 根据主键更新实体
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public <T> void updateEntityById(Class entityName, Serializable id) {
		updateEntitie(get(entityName, id));
	}

	/**
	 * 通过hql 查询语句查找对象
	 *
	 * @param <T>
	 * @param query
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByQueryString(final String query) {

		Query queryObject = getSession().createQuery(query);
		List<T> list = queryObject.list();
		if (list.size() > 0) {
			getSession().flush();
		}
		return list;

	}

	/**
	 * 通过hql查询唯一对象
	 *
	 * @param <T>
	 * @param query
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T singleResult(String hql) {
		T t = null;
		Query queryObject = getSession().createQuery(hql);
		List<T> list = queryObject.list();
		if (list.size() == 1) {
			getSession().flush();
			t = list.get(0);
		} else if (list.size() > 0) {
			throw new BusinessException("查询结果数:" + list.size() + "大于1");
		}
		return t;
	}

	/**
	 * 通过hql 查询语句查找HashMap对象
	 *
	 * @param <T>
	 * @param query
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public Map<Object, Object> getHashMapbyQuery(String hql) {

		Query query = getSession().createQuery(hql);
		List list = query.list();
		Map<Object, Object> map = new HashMap<Object, Object>();
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			Object[] tm = (Object[]) iterator.next();
			map.put(tm[0].toString(), tm[1].toString());
		}
		return map;

	}

	/**
	 * 通过sql更新记录
	 *
	 * @param <T>
	 * @param query
	 * @return
	 */
	public int updateBySqlString(final String query) {

		Query querys = getSession().createSQLQuery(query);
		return querys.executeUpdate();
	}

	/**
	 * 通过sql查询语句查找对象
	 *
	 * @param <T>
	 * @param query
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> findListbySql(final String sql) {
		Query querys = getSession().createSQLQuery(sql);
		return querys.list();
	}

	/**
	 * 创建Criteria对象，有排序功能。
	 *
	 * @param <T>
	 * @param entityClass
	 * @param orderBy
	 * @param isAsc
	 * @param criterions
	 * @return
	 */
	private <T> Criteria createCriteria(Class<T> entityClass, boolean isAsc, Criterion... criterions) {
		Criteria criteria = createCriteria(entityClass, criterions);
		if (isAsc) {
			criteria.addOrder(Order.asc("asc"));
		} else {
			criteria.addOrder(Order.desc("desc"));
		}
		return criteria;
	}

	/**
	 * 创建Criteria对象带属性比较
	 *
	 * @param <T>
	 * @param entityClass
	 * @param criterions
	 * @return
	 */
	private <T> Criteria createCriteria(Class<T> entityClass, Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(entityClass);
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		return criteria;
	}

	@SuppressWarnings("unchecked")
	public <T> List<T> loadAll(final Class<T> entityClass) {
		Criteria criteria = createCriteria(entityClass);
		return criteria.list();
	}

	/**
	 * 创建单一Criteria对象
	 *
	 * @param <T>
	 * @param entityClass
	 * @param criterions
	 * @return
	 */
	private <T> Criteria createCriteria(Class<T> entityClass) {
		Criteria criteria = getSession().createCriteria(entityClass);
		return criteria;
	}

	/**
	 * 根据属性名和属性值查询. 有排序
	 *
	 * @param <T>
	 * @param entityClass
	 * @param propertyName
	 * @param value
	 * @param orderBy
	 * @param isAsc
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findByPropertyisOrder(Class<T> entityClass, String propertyName, Object value, boolean isAsc) {
		Assert.hasText(propertyName);
		return createCriteria(entityClass, isAsc, Restrictions.eq(propertyName, value)).list();
	}

	/**
	 * 根据属性名和属性值 查询 且要求对象唯一.
	 *
	 * @return 符合条件的唯一对象.
	 */
	@SuppressWarnings("unchecked")
	public <T> T findUniqueBy(Class<T> entityClass, String propertyName, Object value) {
		Assert.hasText(propertyName);
		return (T) createCriteria(entityClass, Restrictions.eq(propertyName, value)).uniqueResult();
	}

	/**
	 * 根据查询条件与参数列表创建Query对象
	 *
	 * @param session
	 *            Hibernate会话
	 * @param hql
	 *            HQL语句
	 * @param objects
	 *            参数列表
	 * @return Query对象
	 */
	public Query createQuery(Session session, String hql, Object... objects) {
		Query query = session.createQuery(hql);
		if (objects != null) {
			for (int i = 0; i < objects.length; i++) {
				query.setParameter(i, objects[i]);
			}
		}
		return query;
	}

	/**
	 * 批量插入实体
	 *
	 * @param clas
	 * @param values
	 * @return
	 */
	public <T> int batchInsertsEntitie(List<T> entityList) {
		int num = 0;
		for (int i = 0; i < entityList.size(); i++) {
			save(entityList.get(i));
			num++;
		}
		return num;
	}

	/**
	 * 根据实体名返回全部对象
	 *
	 * @param <T>
	 * @param hql
	 * @param size
	 * @return
	 */
	/**
	 * 使用占位符的方式填充值 请注意：like对应的值格式："%"+username+"%" Hibernate Query
	 *
	 * @param hibernateTemplate
	 * @param hql
	 * @param valus
	 *            占位符号?对应的值，顺序必须一一对应 可以为空对象数组，但是不能为null
	 * @return 2008-07-19 add by liuyang
	 */
	@SuppressWarnings("unchecked")
	public List<T> executeQuery(final String hql, final Object[] values) {
		Query query = getSession().createQuery(hql);
		// query.setCacheable(true);
		for (int i = 0; values != null && i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.list();

	}

	/**
	 * 根据实体模版查找
	 *
	 * @param entityName
	 * @param exampleEntity
	 * @return
	 */

	@SuppressWarnings("rawtypes")
	public List findByExample(final String entityName, final Object exampleEntity) {
		Assert.notNull(exampleEntity, "Example entity must not be null");
		Criteria executableCriteria = (entityName != null ? getSession().createCriteria(entityName) : getSession().createCriteria(exampleEntity.getClass()));
		executableCriteria.add(Example.create(exampleEntity));
		return executableCriteria.list();
	}

	// 使用指定的检索标准获取满足标准的记录数
	public Integer getRowCount(DetachedCriteria criteria) {
		return oConvertUtils.getInt(((Criteria) criteria.setProjection(Projections.rowCount())).uniqueResult(), 0);
	}

	/**
	 * 调用存储过程
	 */
	public void callableStatementByName(String proc) {
	}

	/**
	 * 查询指定实体的总记录数
	 *
	 * @param clazz
	 * @return
	 */
	public int getCount(Class<T> clazz) {

		int count = DataAccessUtils.intResult(getSession().createQuery("select count(*) from " + clazz.getName()).list());
		return count;
	}


	@Autowired
	@Qualifier("jdbcTemplate")
	private JdbcTemplate jdbcTemplate;


	/**
	 * 使用指定的检索标准检索数据并分页返回数据
	 */
	public List<Map<String, Object>> findForJdbc(String sql, int page, int rows) {
		//封装分页SQL
		sql = JdbcDao.jeecgCreatePageSql(sql,page,rows);
		return this.jdbcTemplate.queryForList(sql);
	}


	/**
	 * 使用指定的检索标准检索数据并分页返回数据
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	public <T> List<T> findObjForJdbc(String sql, int page, int rows,Class<T> clazz) {
		List<T> rsList = new ArrayList<T>();
		//封装分页SQL
		sql = JdbcDao.jeecgCreatePageSql(sql,page,rows);
		List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);

		T po = null;
		for(Map<String,Object> m:mapList){
			try {
				po = clazz.newInstance();
				MyBeanUtils.copyMap2Bean_Nobig(po, m);
				rsList.add(po);
			}  catch (Exception e) {
				e.printStackTrace();
			}
		}
		return rsList;
	}

	/**
	 * 使用指定的检索标准检索数据并分页返回数据-采用预处理方式
	 *
	 * @param criteria
	 * @param firstResult
	 * @param maxResults
	 * @return
	 * @throws org.springframework.dao.DataAccessException
	 */
	public  List<Map<String, Object>>  findForJdbcParam(String  sql,  int page, int rows,Object... objs){
		//封装分页SQL
		sql = JdbcDao.jeecgCreatePageSql(sql,page,rows);
		return this.jdbcTemplate.queryForList(sql,objs);
	}
	/**
	 * 使用指定的检索标准检索数据并分页返回数据For JDBC
	 */
	@SuppressWarnings("deprecation")
	public Long getCountForJdbc(String  sql) {
		return  this.jdbcTemplate.queryForLong(sql);
	}
	/**
	 * 使用指定的检索标准检索数据并分页返回数据For JDBC-采用预处理方式
	 *
	 */
	@SuppressWarnings("deprecation")
	public Long getCountForJdbcParam(String  sql,Object[] objs) {
		return  this.jdbcTemplate.queryForLong(sql, objs);
	}

	public List<Map<String, Object>> findForJdbc(String sql, Object... objs) {
		return this.jdbcTemplate.queryForList(sql,objs);
	}


	public Integer executeSql(String sql, Object... param) {
		return this.jdbcTemplate.update(sql,param);
	}

	@SuppressWarnings("deprecation")
	public Integer countByJdbc(String sql, Object... param) {
		return this.jdbcTemplate.queryForInt(sql, param);
	}

	public Map<String, Object> findOneForJdbc(String sql, Object... objs) {
		try{
			return this.jdbcTemplate.queryForMap(sql, objs);
		}catch (EmptyResultDataAccessException e) {
		    return null;
		}
	}

	/**
	 * 通过hql 查询语句查找对象
	 *
	 * @param <T>
	 * @param query
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findHql(String hql, Object... param) {
		Query q = getSession().createQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return q.list();
	}

	/**
	 * 通过hql map方式传参
	 *
	 * @param <T>
	 * @param query
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findHql(String hql, Map<String,Object> param) {
		Query q = getSession().createQuery(hql);
		if (param != null && !param.isEmpty()) {
			for (String key : param.keySet()) {
				q.setParameter(key, param.get(key));
			}
		}
		return q.list();
	}

	/**
	 * 执行HQL语句操作更新
	 * @param hql
	 * @return
	 */
	public Integer executeHql(String hql) {
		Query q = getSession().createQuery(hql);
		return q.executeUpdate();
	}


	@Override
	public <T> List<T> findList(String hql, String keyWord,
			Integer currentPage, Integer numPerPage, String orderField,
			String orderDirection) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}


	/**
	 * easyui分页
	 * @param hql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> find(String hql, int page, int rows) {
		Query q = getSession().createQuery(hql);
		return q.setFirstResult((page-1)*rows).setMaxResults(rows).list();
	}

	@Override
	public <T> Set<T> findSet(String hql, int page, int rows) {
		Query q = getSession().createQuery(hql);
		return (Set<T>) q.setFirstResult((page-1)*rows).setMaxResults(rows).list();
	}

	/**
	 * easyui带参分页
	 * @param hql,param
	 * @return
	 *
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> find(String hql, int page, int rows,
			Map<String, Object> param) {
		Query q = getSession().createQuery(hql);
		if(param!=null && !param.isEmpty()){
			for(String key : param.keySet()){
				q.setParameter(key, param.get(key));
			}
		}
		return q.setFirstResult((page-1)*rows).setMaxResults(rows).list();
	}

	/**
	 * 通过栏目id找到内容,
	 * 按照时间顺序找到前X条数据
	 * @param hql
	 * @param page
	 * @param rows
	 * @param param
	 * @return
	 */
	@Override
	public <T> List<T> find4channelid(String hql, int page, int rows,
			Map<String, Object> param) {
		Query q = getSession().createQuery(hql);
		if(param!=null && !param.isEmpty()){
			for(String key : param.keySet()){
				q.setParameter(key, param.get(key));
			}
		}
		return q.setFirstResult(page).setMaxResults(rows).list();
	}

	@Transactional
	@Override
	public <T> T saveInsertRow(T entity) {
		try {
			getSession().save(entity);
			getSession().flush();
			if (logger.isDebugEnabled()) {
				logger.debug("保存实体成功," + entity.getClass().getName());
			}
		} catch (RuntimeException e) {
			logger.error("保存实体异常", e);
			throw e;
		}
		return entity;
	}

	@Override
	public <T> T updateRow(T entity) {
		getSession().update(entity);
		getSession().flush();
		return entity;
	}

    @Override
    public <T> T updateRow4merge(T entity) {
        getSession().clear();
        getSession().update(entity);
        getSession().flush();
        return entity;
    }


    @Override
	public <T> List<T> findHql4OpenSession(String hql, Object... param) {
		Query q = null;
		Session session = sessionFactory.openSession();
		try {
			q = sessionFactory.openSession().createQuery(hql);
			if (param != null && param.length > 0) {
				for (int i = 0; i < param.length; i++) {
					q.setParameter(i, param[i]);
				}
			}
		} catch (HibernateException e) {
			e.printStackTrace();
		}finally{
				session.disconnect();
		}
		return  q.list();
	}


	public int countAll1(String hql,Map<String,Object> param) {
		Query q = getSession().createQuery(hql);
		if(param!=null && !param.isEmpty()){
			for(String key : param.keySet()){
				q.setParameter(key, param.get(key));
			}
		}
		return q.list().size();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> find4pre(String hql, int page, int rows, Map<String, Object> param) {
		Query q = getSession().createQuery(hql);
		if(param!=null && !param.isEmpty()){
			for(String key : param.keySet()){
				q.setParameter(key, param.get(key));
			}
		}
		return q.setFirstResult(page).setMaxResults(rows).list();
	}



}
